package com.zjxny.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.transaction.Transactional;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import com.zjxny.exception.TrafficException;
import com.zjxny.model.AccountInfo;
import com.zjxny.model.CarInfo;
import com.zjxny.model.CustomerInfo;
import com.zjxny.service.CarInfoService;
import com.zjxny.vo.CarInfoVO;
import com.zjxny.vo.OperationCarInfoVO;
import com.zjxny.vo.ResponseDataVO;
import com.zjxny.vo.ResponseSimpleVO;
import com.zjxny.vo.ResponseVO;

import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import xyz.erupt.jpa.dao.EruptDao;

/**
 * 获取车辆详情
 */
@Slf4j
@Service
public class CarInfoServiceImpl implements CarInfoService {
	@Resource
	private EruptDao eruptDao;
	
	@Resource
	private JdbcTemplate jdbcTemplate;
	
	@Value("${traffic.sleep:1000}")
	Long sleepTime;
	
	String cookies;

	private void initCookies(String cookieStr) {
		JSONArray arr = JSONUtil.parseArray(cookieStr);
		List<String> cookieArr = arr.stream().map(s -> {
			JSON t = (JSON) s;
			return String.format("%s=%s", t.getByPath("name", String.class), t.getByPath("value", String.class));
		}).collect(Collectors.toList());
		cookies=StrUtil.join("; ", cookieArr);
	}
	
	@Override
	@Modifying
	@Transactional
//	@Async("taskExecutor")
	public void getCarList(Long accountId) throws TrafficException {
		AccountInfo accountInfo = eruptDao.queryEntity(AccountInfo.class, "id="+accountId+" and isValid=1");

		String cookieStr = accountInfo.getCookies();
		if(StrUtil.isBlankIfStr(cookieStr)) {
			String accountToUser = null!=accountInfo?accountInfo.getNotifyCpName():"";
			String accountName = null!=accountInfo?accountInfo.getSimpleTitle():"";
			throw new TrafficException("会话失效", -1,accountToUser,accountName);
		}

		initCookies(cookieStr);

		String domain = accountInfo.getDomain();
		String url = String.format("https://%s/user/m/userinfo/vehs", domain);
		String referer = String.format("https://%s/views/memfyy/vehinfo.html?index=7", domain);
		
		HttpRequest request = HttpRequest.post(url).header("Referer", referer);
		request.header("Cookie",cookies);
		request.header("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36");
		
		MapBuilder<String, Object> builder = MapUtil.builder(new HashMap<String, Object>())
				.put("page", "1")
				.put("size", "10")
				.put("status", "null")//根据状态来查询
				.put("hphm", "")
				.put("hpzl", "52");
		HttpResponse response = request.form(builder.build()).execute();
		log.info("carinfo.page=1,response={}",response.body());

		//会话超时 退出登录 抛出异常
		if(response.getStatus() ==302) {
			updateAccountInfoStatus(accountInfo);
			
			String accountToUser = null!=accountInfo?accountInfo.getNotifyCpName():"";
			String accountName = null!=accountInfo?accountInfo.getSimpleTitle():"";
			
			throw new TrafficException("会话失效", -1,accountToUser,accountName);
		}
		
		ResponseVO<CarInfoVO> result = JSONUtil.toBean(response.body(), new TypeReference<ResponseVO<CarInfoVO>>() {}, false);
		if(result.getCode() ==200) {
			ResponseDataVO<CarInfoVO> data = result.getData();
			syncCar2DB(data.getContent(),accountInfo,false,true,false);

			//最后一页 直接退出
			if(data.getLast()) {
				return;
			}

			//TODO 测试阶段先关闭
			for(int i=2;i<=data.getTotalPages();i++) {
				if(sleepTime>0) {					
					long random = RandomUtil.randomLong(sleepTime);
					try {
						Thread.sleep(random);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				builder.clear();
				builder.put("page", ""+i)
				.put("size", "10")
				.put("status", "null")//根据状态来查询
				.put("hphm", "")
				.put("hpzl", "52");
				
				request = HttpRequest.post(url).header("Referer", referer);
				request.header("Cookie",cookies);
				request.header("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36");
				response = request.form(builder.build()).execute();
				
				if(response.getStatus() ==302) {
					updateAccountInfoStatus(accountInfo);
					String accountToUser = null!=accountInfo?accountInfo.getNotifyCpName():"";
					String accountName = null!=accountInfo?accountInfo.getSimpleTitle():"";
					throw new TrafficException("会话失效", -1,accountToUser,accountName);
				}
				log.info("carinfo.page={},response={}",i,response.body());

				result = JSONUtil.toBean(response.body(), new TypeReference<ResponseVO<CarInfoVO>>() {}, false);
				List<CarInfoVO> carInfos = result.getData().getContent();
				syncCar2DB(carInfos,accountInfo,false,true,false);
			}
		}
	}

	/**
	 * 获取营运车辆信息
	 * /user/m/transpcorp/queryvehbind
	 * syxz=&zt=&hpzl=&dbywlx=&yjzt=&fzxh=&random=mdlnotoinfo&page=1&size=10
	 *
	 * @param accountId
	 */
	@Override
	@Modifying
	@Transactional
//	@Async("taskExecutor")
	public void getOperationCarList(Long accountId) throws TrafficException{
		AccountInfo accountInfo = eruptDao.queryEntity(AccountInfo.class, "id="+accountId+" and isValid=1");
		String cookieStr = accountInfo.getCookies();
		if(StrUtil.isBlankIfStr(cookieStr)) {
			log.error("---账号已失效--");
			String accountToUser = null!=accountInfo?accountInfo.getNotifyCpName():"";
			String accountName = null!=accountInfo?accountInfo.getSimpleTitle():"";
			throw new TrafficException("会话失效", -1,accountToUser,accountName);
		}

		initCookies(cookieStr);

		String domain = accountInfo.getDomain();
		String url = String.format("https://%s/user/m/transpcorp/queryvehbind", domain);
		String referer = String.format("https://%s/views/memyy/motoinfo.html?sfsy=1", domain);

		HttpRequest request = HttpRequest.post(url).header("Referer", referer);
		request.header("Cookie",cookies);
		request.header("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36");

		MapBuilder<String, Object> builder = MapUtil.builder(new HashMap<String, Object>())
				.put("page", "1")
				.put("size", "10")
				.put("syxz", "")
				.put("zt", "")
				.put("dbywlx", "")
				.put("yjzt", "")
				.put("fzxh", "")
				.put("random", "mdlnotoinfo")
				.put("hpzl", "");
		HttpResponse response = request.form(builder.build()).execute();
		log.info("getOperationCarList.page=1,response={}",response.body());

		//会话超时 退出登录 抛出异常
		if(response.getStatus() ==302) {
			updateAccountInfoStatus(accountInfo);
			return;
		}
		String responseBody = response.body();
		ResponseVO<OperationCarInfoVO> result = JSONUtil.toBean(responseBody, new TypeReference<ResponseVO<OperationCarInfoVO>>() {}, false);
		if(result.getCode().intValue()==200) {
			ResponseDataVO<OperationCarInfoVO> data = result.getData();

			List<CarInfoVO> carinfos = data.getContent().stream().map(CarInfoServiceImpl::convertToCarInfoVO).collect(Collectors.toList());
			
			syncCar2DB(carinfos,accountInfo,true,false,false);

			if(data.getLast()) {
				return;
			}

			for(int i=2;i<=data.getTotalPages();i++) {
				
				if(sleepTime>0) {
					long random = RandomUtil.randomLong(sleepTime);
					try {
						Thread.sleep(random);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				
				builder.clear();
				builder.put("page", i)
						.put("size", "10")
						.put("syxz", "")
						.put("zt", "")
						.put("dbywlx", "")
						.put("yjzt", "")
						.put("fzxh", "")
						.put("random", "mdlnotoinfo")
						.put("hpzl", "");

				request = HttpRequest.post(url).header("Referer", referer);
				request.header("Cookie",cookies);
				request.header("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36");
				response = request.form(builder.build()).execute();

				if(response.getStatus() ==302) {
					updateAccountInfoStatus(accountInfo);
					return;
				}
				log.info("getOperationCarList={},response={}",i,response.body());

				result = JSONUtil.toBean(response.body(), new TypeReference<ResponseVO<OperationCarInfoVO>>() {}, false);
				carinfos = result.getData().getContent().stream().map(CarInfoServiceImpl::convertToCarInfoVO).collect(Collectors.toList());
				syncCar2DB(carinfos,accountInfo,true,false,false);
			}
		}
	}
	
	/**
	 * 业务办理
	 */
	@Override
	@Modifying
	@Transactional
	public void getBizCarList(Long accountId) throws TrafficException {
			AccountInfo accountInfo = eruptDao.queryEntity(AccountInfo.class, "id="+accountId+" and isValid=1");

		String cookieStr = accountInfo.getCookies();
		if(StrUtil.isBlankIfStr(cookieStr)) {
			String accountToUser = null!=accountInfo?accountInfo.getNotifyCpName():"";
			String accountName = null!=accountInfo?accountInfo.getSimpleTitle():"";
			throw new TrafficException("会话失效", -1,accountToUser,accountName);
		}

		initCookies(cookieStr);

		String domain = accountInfo.getDomain();
		String url = String.format("https://%s/user/m/rentveh/vehlist", domain);
		String referer = String.format("https://%s/views/memrent/vehlist.html", domain);
		
		HttpRequest request = HttpRequest.post(url).header("Referer", referer);
		request.header("Cookie",cookies);
		request.header("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36");
		
		MapBuilder<String, Object> builder = MapUtil.builder(new HashMap<String, Object>())
				.put("page", "1")
				.put("size", "10")
				.put("zt", "")
				.put("hpzl", "52");
		HttpResponse response = request.form(builder.build()).execute();
		log.info("biz.carinfo.page=1,response={}",response.body());

		//会话超时 退出登录 抛出异常
		if(response.getStatus() ==302) {
			updateAccountInfoStatus(accountInfo);			
			String accountToUser = null!=accountInfo?accountInfo.getNotifyCpName():"";
			String accountName = null!=accountInfo?accountInfo.getSimpleTitle():"";			
			throw new TrafficException("会话失效", -1,accountToUser,accountName);
		}
		
		ResponseVO<CarInfoVO> result = JSONUtil.toBean(response.body(), new TypeReference<ResponseVO<CarInfoVO>>() {}, false);
		if(result.getCode() ==200) {
			ResponseDataVO<CarInfoVO> data = result.getData();
			syncCar2DB(data.getContent(),accountInfo,false,false,true);

			//最后一页 直接退出
			if(data.getLast()) {
				return;
			}

			for(int i=2;i<=data.getTotalPages();i++) {
				if(sleepTime>0) {					
					long random = RandomUtil.randomLong(sleepTime);
					try {
						Thread.sleep(random);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				builder.clear();
				builder.put("page", ""+i)
				.put("size", "10")
				.put("zt", "")
				.put("hpzl", "52");
				
				request = HttpRequest.post(url).header("Referer", referer);
				request.header("Cookie",cookies);
				request.header("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36");
				response = request.form(builder.build()).execute();
				
				if(response.getStatus() ==302) {
					updateAccountInfoStatus(accountInfo);
					String accountToUser = null!=accountInfo?accountInfo.getNotifyCpName():"";
					String accountName = null!=accountInfo?accountInfo.getSimpleTitle():"";
					throw new TrafficException("会话失效", -1,accountToUser,accountName);
				}
				log.info("biz.carinfo.page={},response={}",i,response.body());
				result = JSONUtil.toBean(response.body(), new TypeReference<ResponseVO<CarInfoVO>>() {}, false);
				List<CarInfoVO> carInfos = result.getData().getContent();
				syncCar2DB(carInfos,accountInfo,false,false,true);
			}
		}
	}
	

	/**
	 * 获取业务车辆详情 主要是用来获取XH
	 */
	@Override
	public void getBizCarDetail(CarInfoVO carInfo, AccountInfo account) throws TrafficException {
		String cookieStr = account.getCookies();
		if(StrUtil.isBlankIfStr(cookieStr)) {
			String accountToUser = null!=account?account.getNotifyCpName():"";
			String accountName = null!=account?account.getSimpleTitle():"";
			throw new TrafficException("会话失效", -1,accountToUser,accountName);
		}

		initCookies(cookieStr);
		
		String domain = account.getDomain();
		String url = String.format("https://%s/user/m/rentveh/vehdetail", domain);
		String referer = String.format("https://%s/views/memrent/vehlist.html", domain);
		
		HttpRequest request = HttpRequest.post(url).header("Referer", referer);
		request.header("Cookie",cookies);
		request.header("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36");
		
		MapBuilder<String, Object> builder = MapUtil.builder(new HashMap<String, Object>())
				.put("hphm",carInfo.getHphm())
				.put("hpzl", "52");
		HttpResponse response = request.form(builder.build()).execute();
		log.info("biz.cardetail.page=1,response={}",response.body());

		//会话超时 退出登录 抛出异常
		if(response.getStatus() ==302) {
			updateAccountInfoStatus(account);
			String accountToUser = null!=account?account.getNotifyCpName():"";
			String accountName = null!=account?account.getSimpleTitle():"";
			throw new TrafficException("会话失效", -1,accountToUser,accountName);
		}
		
		ResponseSimpleVO<CarInfoVO> result = JSONUtil.toBean(response.body(), new TypeReference<ResponseSimpleVO<CarInfoVO>>() {}, false);
		if(result.getCode() ==200) {
			carInfo.setXh(result.getData().getXh());//重新赋值 xh
		}
	}

	public static CarInfoVO convertToCarInfoVO(OperationCarInfoVO carInfo) {
		CarInfoVO t = new CarInfoVO();
		BeanUtils.copyProperties(carInfo, t);
		return t;
	}

	@Modifying
	@Transactional
	public void updateAccountInfoStatus(AccountInfo accountInfo) {
		cookies="";
		jdbcTemplate.update("update account_info set is_valid=0 where id = "+accountInfo.getId());
	}

	/**
	 * 同步数据至数据库中
	 * 
	 * @param carInfos
	 */
	@Modifying
	@Transactional
	public void syncCar2DB(List<CarInfoVO> carInfos, AccountInfo accountInfo,Boolean isOperation,Boolean isNotOperation,Boolean isBiz)  throws TrafficException{
		if(null==carInfos || carInfos.isEmpty()) {
			return;
		}

		for (CarInfoVO carInfoVO : carInfos) {
			CarInfo carInfo = eruptDao.queryEntity(CarInfo.class, "hphm='"+carInfoVO.getHphm()+"'");
			if(null == carInfo) {
				carInfo = new CarInfo();
				BeanUtils.copyProperties(carInfoVO,carInfo);
				
				carInfo.setIsOperation(isOperation);
				carInfo.setIsNotOperation(isNotOperation);				
				carInfo.setIsBiz(isBiz);
				
				//更新XH字段
				if(isBiz) {
					getBizCarDetail(carInfoVO,accountInfo);
				} else {
					//非业务车辆才能获取 获取机动车合格证
					String certJson = getCert(accountInfo.getId(), carInfoVO.getXh());
					JSONObject certNode = JSONUtil.parseObj(certJson);
					if(certNode.containsKey("result") && certNode.getByPath("$.result.clsbdh")!=null) {
						String vin = certNode.getByPath("$.result.clsbdh",String.class);
						String prefix = StrUtil.sub(vin, 0, vin.length() - 6);
				        String maskedChars = StrUtil.repeat('*', prefix.length());
				        String vinMask = maskedChars + StrUtil.sub(vin,prefix.length(),vin.length());				        
						carInfo.setClsbdh(vin);
						carInfo.setClsbdhMask(vinMask);				
						carInfo.setSyxzStr(certNode.getByPath("$.result.syxzStr",String.class));
						carInfo.setJyhgbzbh(certNode.getByPath("$.result.jyhgbzbh",String.class));
						carInfo.setCjdw(certNode.getByPath("$.result.cjdw",String.class));
					}
				}
				
				//TODO 存在多台车的可能性，如何处理
				//新加顾客资料
				CustomerInfo customerInfo = eruptDao.queryEntity(CustomerInfo.class, "carNo='"+carInfoVO.getHphm()+"' and isValid=1");
				if(null!= customerInfo) {
					carInfo.setCustomerInfo(customerInfo);
				}
			}
			
			//会覆盖旧的属性
			BeanUtils.copyProperties(carInfoVO,carInfo,"isOperation","clsbdh");
			
			carInfo.setAccountInfo(accountInfo);
			eruptDao.persist(carInfo);
		}
		eruptDao.flush();
	}

	@Override
	public String getCert(AccountInfo accountInfo, String xh) throws TrafficException {
		String url = String.format("https://%s/m/electronicCertificate/getCert?lx=%d&xh=%s", accountInfo.getDomain(),1,xh);
		String referer = String.format("https://%s/views/memyy/dzhgbz.html?xh=", accountInfo.getDomain(),xh);
		
		String cookieStr = accountInfo.getCookies();
		initCookies(cookieStr);
		
		HttpRequest request = HttpRequest.get(url).header("Referer", referer);
		request.header("Cookie",cookies);
		request.header("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36");
		HttpResponse response = request.execute();
		
		if(response.getStatus() ==302) {
			updateAccountInfoStatus(accountInfo);
			String accountToUser = null!=accountInfo?accountInfo.getNotifyCpName():"";
			String accountName = null!=accountInfo?accountInfo.getSimpleTitle():"";
			log.warn("getCert:{}",response);
			throw new TrafficException("会话失效", -1,accountToUser,accountName);
		}
		
		String responseBody = response.body();
		log.info("getCert,response={}",response.body());
		return responseBody;
	}
	
	/**
	 * 获取机动车检验合格证详情资料
	 */
	@Deprecated
	@Override
	public String getCert(Long accountId,String xh) throws TrafficException{
		Map<String,Object> map = jdbcTemplate.queryForMap("select domain,cookies from account_info where id="+accountId);
		
//		String domain = jdbcTemplate.queryForObject("select domain,cookies from account_info where id="+accountId, String.class);
		String domain = (String) map.get("domain");
		String cookieStr =(String) map.get("cookies");
		initCookies(cookieStr);
		String url = String.format("https://%s/m/electronicCertificate/getCert?lx=%d&xh=%s", domain,1,xh);
		String referer = String.format("https://%s/views/memyy/dzhgbz.html?xh=", domain,xh);
		HttpRequest request = HttpRequest.get(url).header("Referer", referer);
		request.header("Cookie",cookies);
		request.header("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36");
		
		HttpResponse response = request.execute();
		String responseBody = response.body();
		
		log.info("getCert,response={}",response.body());
		return responseBody;
	}
	
	@Override
	public String vehqrcode(AccountInfo accountInfo, String hphm) throws TrafficException {
		String url = String.format("https://%s/user/m/userinfo/vehqrcode", accountInfo.getDomain());
		String referer = String.format("https://%s/views/memfyy/vehinfo.html?index=7", accountInfo.getDomain());
		
		String cookieStr = accountInfo.getCookies();
		initCookies(cookieStr);
		
		HttpRequest request = HttpRequest.post(url).header("Referer", referer);
		request.header("Cookie",cookies);
		request.header("User-Agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36");
		
		MapBuilder<String, Object> builder = MapUtil.builder(new HashMap<String, Object>())
				.put("hphm", hphm)
				.put("hpzl", "52");
		HttpResponse response = request.form(builder.build()).execute();
		
		if(response.getStatus() ==302) {
			updateAccountInfoStatus(accountInfo);
			String accountToUser = null!=accountInfo?accountInfo.getNotifyCpName():"";
			String accountName = null!=accountInfo?accountInfo.getSimpleTitle():"";
			log.warn("vehqrcode:{}",response);
			throw new TrafficException("会话失效", -1,accountToUser,accountName);
		}
		
		String responseBody = response.body();
		log.info("vehqrcode,response={}",response.body());
		return responseBody;
	}
}
